/*  File    : sim_sfunc.c
 *  Abstract:
 *
 *
 *  Copyright 1990-2013 The MathWorks, Inc.
 */
#define S_FUNCTION_NAME sim_foc
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
#include "tmwtypes.h"

extern void sim_sfunc_init(SimStruct *S);
extern void sim_sfunc_terminate(SimStruct *S);
extern void sim_sfunc_core(SimStruct *S);
extern void sim_sfunc_output(SimStruct *S);

extern int_T simGetInPortNums(void);
extern int_T simGetInPortNumWidth(int port);
extern int_T simGetOutPortNums(void);
extern int_T simGetOutPortNumWidth(int port);

/*====================*
 * S-function methods *
 *====================*/

/* Function: mdlInitializeSizes ===============================================
 * Abstract:
 *    The sizes information is used by Simulink to determine the S-function
 *    block's characteristics (number of inputs, outputs, states, etc.).
 */
static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, 0);  /* Number of expected parameters */
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        return; /* Parameter mismatch will be reported by Simulink */
    }

    ssSetNumContStates(S, 0);
    ssSetNumDiscStates(S, 0);

    if (!ssSetNumInputPorts(S, simGetInPortNums())) return;
    for (int port = 0; port < simGetInPortNums(); port++) {
        ssSetInputPortWidth(S, port, simGetInPortNumWidth(port));
        ssSetInputPortDirectFeedThrough(S, port, 1);
    }
    
    if (!ssSetNumOutputPorts(S, simGetOutPortNums())) return;
    for (int port = 0; port < simGetOutPortNums(); port++) {
        ssSetOutputPortWidth(S, port, simGetOutPortNumWidth(port));
    }
    ssSetNumSampleTimes(S, 1);
    ssSetNumRWork(S, 0);
    ssSetNumIWork(S, 0);
    ssSetNumPWork(S, 0);
    ssSetNumModes(S, 0);
    ssSetNumNonsampledZCs(S, 0);
    ssSetOperatingPointCompliance(S, USE_DEFAULT_OPERATING_POINT);
    
    /* Set this S-function as runtime thread-safe for multicore execution */
    ssSetRuntimeThreadSafetyCompliance(S, RUNTIME_THREAD_SAFETY_COMPLIANCE_TRUE);
    
    ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
}



/* Function: mdlInitializeSampleTimes =========================================
 * Abstract:
 *    Specify the sample time as 1.0
 */
static void mdlInitializeSampleTimes(SimStruct *S)
{
    ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
    ssSetOffsetTime(S, 0, 0.0);
    ssSetModelReferenceSampleTimeDefaultInheritance(S);      
}

#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ========================================
 * Abstract:
 *    Initialize both discrete states to one.
 */
static void mdlInitializeConditions(SimStruct *S)
{
    sim_sfunc_init(S);
}

/* Function: mdlOutputs =======================================================
 * Abstract:
 *      y = Cx + Du 
 */

static void mdlOutputs(SimStruct *S, int_T tid)
{
    UNUSED_ARG(tid); /* not used in single tasking mode */
    sim_sfunc_core(S);
    sim_sfunc_output(S);
}



//#define MDL_UPDATE
/* Function: mdlUpdate ======================================================
 * Abstract:
 *      xdot = Ax + Bu
 */
static void mdlUpdate(SimStruct *S, int_T tid)
{
    real_T            *x       = ssGetRealDiscStates(S);
    InputRealPtrsType uPtrs    = ssGetInputPortRealSignalPtrs(S,0);
    UNUSED_ARG(tid); /* not used in single tasking mode */
}



/* Function: mdlTerminate =====================================================
 * Abstract:
 *    No termination needed, but we are required to have this routine.
 */
//extern bool need_exit;
static void mdlTerminate(SimStruct *S)
{
    UNUSED_ARG(S); /* unused input argument */
    sim_sfunc_terminate(S);
}

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif
